﻿using FastBuild.TimeJob;
using Newtonsoft.Json.Linq;
using SqlSugar;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using Wechat_PublicNumber.Common;
using Wechat_PublicNumber.Entity;
using Wechat_PublicNumber.Model;
using Wechat_PublicNumber.Repository;

namespace Wechat_PublicNumber.Jobs
{
    [SkipWhileExecuting]
    public class WechatWorkSupplementBreaksJob : DataAccess, IJob
    {
        [Autowired]
        private IHttpClientFactory _clientFactory;

        [Autowired]
        private WorkRepository _workRepository;

        [Autowired]
        private WxTemplateRepository _templateRepository;

        [Autowired]
        private WxHttpInvoke _wxHttpInvoke;

        private const string _openID = "otCQI6q07YZUqxc06iOqkQVcqeYw";

        public async Task Execute()
        {
            _logger.Info($"WechatWorkSupplementBreaksJob Start", "WechatWorkSupplementBreaksJob");

            try
            {
                var now = DateTime.Now;

                var workString = await GetWeChatWork();

                _logger.Info(workString, "WxWorkInvokeData");

                var workObj = JObject.Parse(workString);

                if (workObj["data"]["xcxdata"] != null)
                {
                    var last7DaysWorkList = workObj["data"]["xcxdata"].ToList();

                    List<Work> addWorkTimes = new List<Work>();
                    List<WeChatWorkHistory> addHistory = new List<WeChatWorkHistory>();
                    var message = "请假记录已更新，";
                    foreach (var oneWork in last7DaysWorkList)
                    {
                        if (oneWork["summary_list"] is null) continue;

                        string spid = oneWork["sp_id"].ToString();
                        if (await WXDb.Queryable<WeChatWorkHistory>().AnyAsync(s => s.SP_ID == spid)) continue;

                        var workStartEndTime = oneWork["summary_list"].ToList();
                        if (workStartEndTime is null || workStartEndTime.Count() != 3) continue;

                        _logger.Info($"{spid} 开始处理：{string.Join(" ", workStartEndTime.Select(s => s.ToString()))}", "WechatWorkSupplementBreaksJob");

                        var workType = workStartEndTime[0].ToString().Split("：")[1];
                        Match match = Regex.Match(workStartEndTime[1].ToString(), @"开始时间：(\d{4}/\d{1,2}/\d{1,2})\s+([上下]午)");
                        var startTime = DateTime.Parse($"{match.Groups[1].Value}");
                        var startMatch = match.Groups[2].Value;

                        match = Regex.Match(workStartEndTime[2].ToString(), @"结束时间：(\d{4}/\d{1,2}/\d{1,2})\s+([上下]午)");
                        var endTime = DateTime.Parse($"{match.Groups[1].Value}");
                        var endMatch = match.Groups[2].Value;

                        var workTime = await GetWorkTime(startTime, endTime);
                        if (workTime != null && workTime.Count > 0)
                        {
                            decimal totalHours = 0;

                            if (startTime == endTime)
                            {
                                var hours = startMatch == "上午" && endMatch == "下午" ? 8 : 4;
                                addWorkTimes.Add(new Work()
                                {
                                    WhichDay = startTime,
                                    OpenID = _openID,
                                    CreateTime = now,
                                    Type = Model.WorkTypeEmnu.SupplementBreaks,
                                    Hours = hours
                                });
                                totalHours += hours;
                            }
                            else
                            {
                                var startDate = workTime.FirstOrDefault(s => s == startTime);
                                if (startDate != DateTime.MinValue)
                                {
                                    var hours = startMatch == "上午" ? 8 : 4;
                                    addWorkTimes.Add(new Work()
                                    {
                                        WhichDay = startDate,
                                        OpenID = _openID,
                                        CreateTime = now,
                                        Type = Model.WorkTypeEmnu.SupplementBreaks,
                                        Hours = hours
                                    });
                                    totalHours += hours;
                                }

                                var endDate = workTime.FirstOrDefault(s => s == endTime);
                                if (endDate != DateTime.MinValue)
                                {
                                    var hours = endMatch == "上午" ? 4 : 8;
                                    addWorkTimes.Add(new Work()
                                    {
                                        WhichDay = endTime,
                                        OpenID = _openID,
                                        CreateTime = now,
                                        Type = Model.WorkTypeEmnu.SupplementBreaks,
                                        Hours = hours
                                    });
                                    totalHours += hours;
                                }
                            }

                            workTime.RemoveAll(s => s == startTime || s == endTime);

                            addWorkTimes.AddRange(
                                workTime.Select(s =>
                                new Work
                                {
                                    WhichDay = s,
                                    OpenID = _openID,
                                    CreateTime = now,
                                    Type = Model.WorkTypeEmnu.SupplementBreaks,
                                    Hours = 8
                                })
                            );

                            totalHours += workTime.Count * 8;

                            addHistory.Add(new WeChatWorkHistory()
                            {
                                SP_ID = spid,
                                CreateTime = now
                            });

                            message += $"时长:{totalHours}h，";

                            _logger.Info($"{spid} 处理完毕", "WechatWorkSupplementBreaksJob");
                        }
                    }

                    await WXDb.Insertable(addWorkTimes).ExecuteCommandAsync();

                    await WXDb.Insertable(addHistory).ExecuteCommandAsync();

                    if (addHistory.Count > 0)
                    {
                        var residueTime = await _workRepository.GetResidueWorkTime(_openID);

                        message += $"剩余调休时长{residueTime}h。";

                        var pushData = await _templateRepository.GetTemplateData(WeChatTemplateEnum.CommonMessage, _openID, new { Message = message });
                        if (pushData is not null) await _wxHttpInvoke.PushTemplate(pushData);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "WechatWorkSupplementBreaksJob Error", "WechatWorkSupplementBreaksJob");
            }

            _logger.Info($"WechatWorkSupplementBreaksJob End", "WechatWorkSupplementBreaksJob");
            GC.Collect();
        }

        private async Task<List<DateTime>> GetWorkTime(DateTime beginTime, DateTime endTime)
        {
            var allWorkDays = new List<DateTime>();

            var holidayList = await WXDb.Queryable<Holiday, HolidayTime>((h, ht) => new object[]
            {
               JoinType.Left,h.ID==ht.HolidayID
            })
            .Where((h, ht) => SqlFunc.Between(ht.Time, beginTime, endTime))
            .Select((h, ht) => new
            {
                ht.Time,
                ht.Type
            })
            .ToListAsync();

            var whilenowDate = beginTime.Date;
            while (whilenowDate <= endTime.Date)
            {
                var holiday = holidayList.FirstOrDefault(s => s.Time == whilenowDate);

                if ((holiday == null && whilenowDate.DayOfWeek != DayOfWeek.Saturday && whilenowDate.DayOfWeek != DayOfWeek.Sunday)
                    || (holiday != null && holiday.Type == Model.HolidayTypeEnum.SupplementWeekday)
                    )
                    allWorkDays.Add(whilenowDate);

                whilenowDate = whilenowDate.AddDays(1);
            }

            return allWorkDays;
        }

        private async Task<string> GetWeChatWork()
        {
            using (var client = _clientFactory.CreateClient())
            {
                var content = new StringContent($"termid=0&offset=0&limit=10&filter=myapply&last_templateid=&keyword=&creator_vid=&read_status=&sp_status=2&start_time={new DateTimeOffset(DateTime.Now.AddDays(-7)).ToUnixTimeSeconds()}&end_time={new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}&template_id=1970325041997444_1688850093292089_1221302970_1498786939");
                content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

                using (HttpRequestMessage requestMessage = new HttpRequestMessage())
                {
                    requestMessage.Method = HttpMethod.Post;
                    requestMessage.RequestUri = new Uri("https://app.work.weixin.qq.com/wework_admin/approval/api/get_approval_list?lang=zh_CN&f=json&ajax=1&random=0.934996314418509");
                    requestMessage.Content = content;

                    requestMessage.Headers.Add("Host", "app.work.weixin.qq.com");
                    requestMessage.Headers.Add("Connection", "keep-alive");
                    requestMessage.Headers.Add("sec-ch-ua", "\"Chromium\";v=\"107\"");
                    requestMessage.Headers.Add("Accept", "application/json, text/javascript, */*; q=0.01");
                    requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest");
                    requestMessage.Headers.Add("sec-ch-ua-mobile", "?0");
                    requestMessage.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 Language/zh wxwork/4.1.6 (MicroMessenger/6.2) WindowsWechat  MailPlugin_Electron WeMail embeddisk");
                    requestMessage.Headers.Add("sec-ch-ua-platform", "\"Windows\"");
                    requestMessage.Headers.Add("Origin", "https://app.work.weixin.qq.com");
                    requestMessage.Headers.Add("Sec-Fetch-Site", "same-origin");
                    requestMessage.Headers.Add("Sec-Fetch-Mode", "cors");
                    requestMessage.Headers.Add("Sec-Fetch-Dest", "empty");
                    requestMessage.Headers.Add("Referer", "https://app.work.weixin.qq.com/wework_admin/approval/desktop/entry");
                    requestMessage.Headers.Add("Accept-Encoding", "gzip, deflate, br");
                    requestMessage.Headers.Add("Accept-Language", "zh-CN,zh;q=0.9");
                    requestMessage.Headers.Add("Cookie", $"wwoa.h5_approval.skey={WXDb.Queryable<WeChatWorkCookie>().Where(s => s.Key == "wwoa.h5_approval.skey").First().Value};wwapp.vid=1688855671348681;");

                    var wxWork = await client.SendAsync(requestMessage);

                    var newCookie = wxWork.Headers.GetValues("Set-Cookie");
                    if (newCookie != null)
                    {
                        var skey = newCookie.FirstOrDefault(s => s.Contains("wwoa.h5_approval.skey"));
                        if (!string.IsNullOrEmpty(skey))
                        {
                            var value = Regex.Match(skey, @"wwoa.h5_approval.skey=([A-Za-z0-9_-]+);").Groups[1].Value;
                            await WXDb.Updateable<WeChatWorkCookie>()
                                .SetColumns(it => new WeChatWorkCookie() { Value = value, Dimport = DateTime.Now })
                                .Where(s => s.Key == "wwoa.h5_approval.skey")
                                .ExecuteCommandAsync();
                        }
                    }

                    return await wxWork.Content.ReadAsStringAsync();
                }
            }   
        }
    }

    class WorkTime
    {
        public DateTime Date { get; set; }

        public int Hours { get; set; }
    }
}
